/*
 * Copyright (c) 2023-2023 elsfs Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.elsfs.cloud.common.mybatis.configuration;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DataChangeRecorderInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elsfs.cloud.common.mybatis.handler.MybatisPlusMetaObjectHandler;
import org.elsfs.cloud.common.mybatis.handler.TenantLineHandlerImpl;
import org.elsfs.cloud.common.mybatis.injector.ElsfsSqlInjector;
import org.elsfs.cloud.common.mybatis.interceptor.MybatisSensitiveInterceptor;
import org.elsfs.cloud.common.mybatis.properties.MybatisPlusProperties;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * mybatis plus 配置
 *
 * @author zeng
 */
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({MybatisPlusProperties.class, SecurityProperties.class})
@Slf4j
@RequiredArgsConstructor
@MapperScan(basePackages = "org.elsfs.cloud.**.mapper")
public class MybatisPlusConfiguration {

  /**
   * 配置 Mybatis Plus 分页插件和其他常用插件，如多租户、乐观锁等。 对于使用了 Mybatis Plus 的项目，建议配置该插件，以提高数据库操作的效率和安全性。
   *
   * <p>在配置多个功能时，需要注意它们的顺序关系，推荐按照以下顺序配置： 多租户 -> 动态表名 -> 分页 -> 乐观锁 -> SQL 性能规范，以避免潜在的数据库性能问题。
   *
   * @param mybatisPlusProperties 项目中配置的 Mybatis Plus 属性，用于获取多租户配置信息。
   * @return 返回配置好的 Mybatis Plus 插件实例。
   */
  @Bean
  public MybatisPlusInterceptor mybatisPlusInterceptor(
      MybatisPlusProperties mybatisPlusProperties) {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    // 动态表名
    // interceptor.addInnerInterceptor(new DynamicTableNameInnerInterceptor());
    // 根据多租户是否启用，添加相应的拦截器
    if (mybatisPlusProperties.getTenant().getEnabled()) {
      interceptor.addInnerInterceptor(
          new TenantLineInnerInterceptor(new TenantLineHandlerImpl(mybatisPlusProperties)));
    }
    // 添加分页拦截器
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
    // 添加乐观锁拦截器
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    // 数据权限处理器
    interceptor.addInnerInterceptor(
        new DataPermissionInterceptor(
            (MultiDataPermissionHandler) (table, where, mappedStatementId) -> null));
    // 添加数据变更记录拦截器
    interceptor.addInnerInterceptor(
        new DataChangeRecorderInnerInterceptor() {
          /**
           * 处理数据变更记录
           *
           * @param operationResult 操作结果
           */
          @Override
          protected void dealOperationResult(OperationResult operationResult) {
            super.dealOperationResult(operationResult);
          }
        });
    LOGGER.info("mybatis plus 拦截器初始化成功");
    return interceptor;
  }

  /**
   * 审计字段自动填充
   *
   * @return {@link MetaObjectHandler}
   */
  @Bean
  public MybatisPlusMetaObjectHandler mybatisPlusMetaObjectHandler() {
    return new MybatisPlusMetaObjectHandler();
  }

  /**
   * 创建并返回一个MybatisSensitiveInterceptor实例。 这个方法没有参数。
   *
   * @return MybatisSensitiveInterceptor - 返回一个MybatisSensitiveInterceptor实例，用于敏感信息的拦截处理。
   */
  @Bean
  public MybatisSensitiveInterceptor mybatisSensitiveInterceptor() {
    return new MybatisSensitiveInterceptor();
  }

  @Bean
  @ConditionalOnMissingBean
  public ISqlInjector elsfsSqlInjector() {
    return new ElsfsSqlInjector();
  }
}
